package com.kaibes.web.security.config;

import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.vote.UnanimousBased;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.kaibes.web.security.core.AuthorityVoter;
import com.kaibes.web.security.core.Token2authentication;
import com.kaibes.web.security.core.TokenAuthorizationFilter;
import com.kaibes.web.security.handler.ForbiddenHandler;
import com.kaibes.web.security.handler.UnauthorizedEntryPoint;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;
    @Autowired
    private UnauthorizedEntryPoint authenticationEntryPoint;
    @Autowired
    private ForbiddenHandler accessDeniedHandler;
    @Autowired
    private AuthorityVoter authorityVoter;
    @Autowired
    private Token2authentication token2authentication;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        if (securityProperties.getWhiteList() != null) {
            for (SecurityWhiteMap whiteMap : securityProperties.getWhiteList()) {
                String[] keys = whiteMap.getUris();
                List<String> ips = whiteMap.getIps();
                if (ips.size() == 1) {
                    http.authorizeRequests().antMatchers(keys).hasIpAddress(ips.get(0));
                } else {
                    StringBuilder sb = new StringBuilder();
                    for (String ip : ips) {
                        sb.append("hasIpAddress('").append(ip).append("') or ");
                    }
                    sb.setLength(sb.length() - 4);
                    http.authorizeRequests().antMatchers(keys).access(sb.toString());
                }
            }
        }

        // =========================================
        http.headers().frameOptions().disable().and().authorizeRequests().accessDecisionManager(accessDecisionManager())
                .anyRequest().permitAll().and()
                .addFilterAfter(new TokenAuthorizationFilter(token2authentication), UsernamePasswordAuthenticationFilter.class)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler).and()
                .formLogin().disable().httpBasic().disable().csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/assets/**");
    }

    @Bean
    public AccessDecisionManager accessDecisionManager() {
//        WebExpressionVoter
//        AuthenticatedVoter
//        PreInvocationAuthorizationAdviceVoter
//        RoleVoter
//        RoleHierarchyVoter
        return new UnanimousBased(Arrays.asList(new WebExpressionVoter(), authorityVoter));
    }

}
